﻿#if !XBOX

using DXInput = Microsoft.DirectX.DirectInput;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using DXJoystickSupport;

namespace DXJoystickSupport
{
    public class DXJoy
    {
        private static List<object> stateLock;

        private static bool loaded = false;
        private static List<DXInput.Device> joystick;

        private static List<DXJoyState> dxJoystickState;

        public static DXJoyState GetState(PlayerIndex playerIndex)
        {
            lock (stateLock[(int)playerIndex])
            {
                return DXJoy.dxJoystickState[(int)playerIndex];
            }
        }

        public static void Load(Game GameInstance)
        {
            stateLock = new List<object>();
            stateLock.Add(new object());
            stateLock.Add(new object());
            stateLock.Add(new object());
            stateLock.Add(new object());
            DXInput.DeviceList joystickList = DXInput.Manager.GetDevices(DXInput.DeviceClass.GameControl, DXInput.EnumDevicesFlags.AttachedOnly);
            dxJoystickState = new List<DXJoyState>();
            dxJoystickState.Add(new DXJoyState());
            dxJoystickState.Add(new DXJoyState());
            dxJoystickState.Add(new DXJoyState());
            dxJoystickState.Add(new DXJoyState());
            if (!joystickList.Count.Equals(0))
            {
                joystick = new List<DXInput.Device>();
                //joystickState = new List<DXInput.JoystickState>();
                DXInput.Device device;
                foreach (DXInput.DeviceInstance deviceInstance in joystickList)
                {
                    device = new DXInput.Device(deviceInstance.InstanceGuid);
                    device.SetCooperativeLevel(GameInstance.Window.Handle, DXInput.CooperativeLevelFlags.Background | DXInput.CooperativeLevelFlags.NonExclusive);
                    device.SetDataFormat(DXInput.DeviceDataFormat.Joystick);
                    device.Acquire();
                    device.Poll();
                    if (deviceInstance.DeviceType.Equals(DXInput.DeviceType.Joystick))
                    {
                        joystick.Add(device);
                        //joystickState.Add(device.CurrentJoystickState);
                    }
                }
            }
            loaded = true;
        }

        public static void Poll()
        {
            if (!loaded)
            {
                throw new Exception("JoystickInput not loaded. Make sure if JoystickInput.Load(this) has present in your Initialize method.");
            }
            int i = 0;
            if (joystick!=null)
            {
                for (i = 0; (i < 4) && (i < joystick.Count); i++)
                {
                    if (joystick[i].Caps.Attatched)
                    {
                        joystick[i].Poll();
                        lock (stateLock[i])
                        {
                            dxJoystickState[i].Update(joystick[i]);
                        }
                    }
                }
            }
        }
        
        public static void Unload()
        {
            if (!loaded)
            {
                throw new Exception("JoystickInput not loaded. Make sure if JoystickInput.Load(this) has present in your Initialize method.");
            }
            int i = 0;
            //joystickState.Clear();
            dxJoystickState.Clear();
            if (joystick != null)
            {
                for (i = 0; i < joystick.Count; i++)
                {
                    joystick[i].Unacquire();
                    joystick[i].Dispose();
                }
                joystick.Clear();
            }
        }
        /*
        public void ApplyForceFeedBack(int[] direcao, int forca)
        {
            int[] axis = null;
            #region enumerate axes
            // Enumerate any axes
            foreach (DeviceObjectInstance doi in device.Objects)
            {
                if ((doi.ObjectId & (int)DeviceObjectTypeFlags.Axis) != 0)
                {
                    // We found an axis, set the range to a max of 10,000
                    device.Properties.SetRange(ParameterHow.ById, doi.ObjectId, new InputRange(-5000, 5000));
                }

                int[] temp;

                // Get info about first two FF axii on the device
                if ((doi.Flags & (int)ObjectInstanceFlags.Actuator) != 0)
                {
                    if (axis != null)
                    {
                        temp = new int[axis.Length + 1];
                        axis.CopyTo(temp, 0);
                        axis = temp;
                    }
                    else
                    {
                        axis = new int[1];
                    }

                    // Store the offset of each axis.
                    axis[axis.Length - 1] = doi.Offset;
                    if (axis.Length == 2)
                    {
                        break;
                    }
                }
            }
            #endregion

            EffectList el = device.GetEffects(EffectType.ConstantForce);
            el.MoveNext();
            EffectInformation ei = (EffectInformation)el.Current;

            Effect e = new Effect();
            e.SetAxes(new int[axis.Length]);
            e.SetDirection(new int[axis.Length]);

            e.EffectType = EffectType.ConstantForce;
            e.ConditionStruct = new Condition[axis.Length];
            e.Duration = 333333;
            e.Gain = forca;
            e.Constant = new ConstantForce();
            e.Constant.Magnitude = forca;
            e.SamplePeriod = 0;
            e.TriggerButton = (int)Microsoft.DirectX.DirectInput.Button.NoTrigger;
            e.TriggerRepeatInterval = (int)DI.Infinite;
            e.Flags = EffectFlags.ObjectOffsets | EffectFlags.Cartesian;
            e.UsesEnvelope = false;
            e.SetAxes(axis);
            e.SetDirection(direcao);

            try
            {
                EffectObject eo = new EffectObject(ei.EffectGuid, e, device);
                eo.Start(1);
            }
            catch { }
        }

        public static void ReloadGamepads()
        {
            //DeviceList devices = Manager.GetDevices(DeviceType.Gamepad,EnumDevicesFlags.AttachedOnly);
            DeviceList devices = Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly | EnumDevicesFlags.ForceFeeback);
            //DeviceList list2 = Manager.GetDevices(DeviceType.Joystick, EnumDevicesFlags.AttachedOnly);
            //gamepads = new List<DirectInputGamepad>(devices.Count + list2.Count);
            gamepads = new List<JoystickInput>(devices.Count);
            foreach (DeviceInstance instance in devices)
            {
                JoystickInput item = new JoystickInput(instance.InstanceGuid);
                gamepads.Add(item);
            }
            //foreach (DeviceInstance instance2 in list2)
            //{
             //   DirectInputGamepad gamepad2 = new DirectInputGamepad(instance2.InstanceGuid);
              //  gamepads.Add(gamepad2);
            //}
        }

        public DirectInputButtons Buttons
        {
            get
            {
                return new DirectInputButtons(this.device);
            }
        }

        public Device Device
        {
            get
            {
                return this.device;
            }
        }

        public string DiagnosticsButtons
        {
            get
            {
                StringBuilder builder = new StringBuilder();
                int num = 0;
                foreach (ButtonState state in this.Buttons.List)
                {
                    builder.Append(num);
                    builder.Append("=");
                    builder.Append((state == ButtonState.Pressed) ? "1" : "0");
                    builder.Append(" ");
                    num++;
                }
                return builder.ToString();
            }
        }

        public string DiagnosticsRawGamepadData
        {
            get
            {
                return string.Concat(new object[] { "X", this.Device.CurrentJoystickState.X, " Y", this.Device.CurrentJoystickState.Y, " Z", this.Device.CurrentJoystickState.Z, " Rx", this.Device.CurrentJoystickState.Rx, " Ry", this.Device.CurrentJoystickState.Ry, " Rz", this.Device.CurrentJoystickState.Rz, " pov[0]", this.Device.CurrentJoystickState.GetPointOfView()[0] });
            }
        }

        public string DiagnosticsThumbSticks
        {
            get
            {
                return string.Concat(new object[] { "X", Math.Round((double)this.ThumbSticks.Left.X, 4), " Y", Math.Round((double)this.ThumbSticks.Left.Y, 4), " X", Math.Round((double)this.ThumbSticks.Right.X, 4), " Y", Math.Round((double)this.ThumbSticks.Right.Y, 4) });
            }
        }

        public DirectInputDPad DPad
        {
            get
            {
                return new DirectInputDPad(this.device.CurrentJoystickState.GetPointOfView()[0]);
            }
        }

        public static List<JoystickInput> Gamepads
        {
            get
            {
                if (gamepads == null)
                {
                    ReloadGamepads();
                }
                return gamepads;
            }
        }

        public DirectInputThumbSticks ThumbSticks
        {
            get
            {
                return new DirectInputThumbSticks(this.device);
            }
        }*/
    }
}
#endif